package com.gitee.wsl.transform.parser

import com.gitee.wsl.func.InvokeCall


fun interface Parser<K,out T>: InvokeCall<K, List<ParseResult<T>>> {
   fun parser(src:K):List<ParseResult<T>>

   override fun invoke(t: K): List<ParseResult<T>> = parser(t)

   companion object
}

/**
 * Returns a parser indicating failure which will fail all parsers applied after it.
 */
fun <K,T> Parser.Companion.fail(): Parser<K,T> = Parser{ emptyList() }


typealias StringParser<T> = Parser<String, T>

typealias ParserChar = StringParser<Char>

typealias ParserString = StringParser<String>

/**
 * val emailDomainParser = parser {
 *         dropWhile(inclusive = true) { it != '@' }
 *         takeAllLeft().bind()
 *     }
 *
 * println(emailDomainParser.parse("iliyan.germanov971@gmail.com"))
 */
fun <T> String.parser(parser: StringParser<T>) = parser.parse(this)


fun <T> String.parser(p: ParseScope.() -> T) = parse(this , p)


fun <T> Parser.Companion.parser(p:  ParseScope.() -> T): StringParser<T> = StringParser { text ->
   val res = parse(text, p)
   if (res != null) listOf(res) else emptyList()
}


internal fun <T> parse(text: String, parserFun:  ParseScope.() -> T): ParseResult<T>? = try {
   val scope = ParseScopeImpl(text)
   val res = with(scope) {
      parserFun()
   }
   ParseResult(value = res, leftover = scope.leftover)
} catch (e: Exception) {
   null
}


fun <T> StringParser<T>.parse(text: String): ParseResult<T>? = try {
   this.parser(text).firstOrNull()
} catch (e: Exception) {
   null
}


